import cv2 as cv
import numpy as np
# 读取检测后分割的单个絮体图像并且计算该絮体的特征


def featureCalculateAd(path):
    # 默认灰度化读取
    image = cv.imread(path, 0)
    # 二值化
    ret, bn = cv.threshold(image, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
    # 找出感兴趣区域
    contours, hierarchy = cv.findContours(bn, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    # 在原图上绘制出感兴趣区域
    for i in contours:
        # 在图上绘制出感兴趣区域
        cv.drawContours(image, i, -1, (255, 255, 0), 5)

    # 计算目标感兴趣区域的大小以及需要的参数 粒径
    # =====================================================
    # x是每个感兴趣点的大小
    # ad是等效直径
    x = 0
    ad = 0
    xlist = []
    for i in contours:
        xlist.append(cv.contourArea(i))
        x += cv.contourArea(i)
    # 所有面积由大到小排序 取第一个最大的面积
    xlist.sort(reverse=True)
    # allAd = ((4 * x) / 3.14) ** 0.5
    maxAd = ((4 * xlist[0]) / 3.14) ** 0.5
    realAd = maxAd / 89 * 100

    return realAd

    # maxAd = ((4 * xlist[0]) / 3.14) ** 0.5
    # print('当前图片上所有面积大小:', x, 'px')
    # print('当前图片上最大面积大小:', xlist[0], 'px')
    # print('当前图片上所有面积等效直径大小:', aveAd, 'px')
    # print('当前图片上最大面积等效直径大小:', maxAd, 'px')
    # print('当前图片上颗粒实际大小:', ad / 89 * 100, 'um')
    # print('当前图片上最大面积颗粒实际大小:', maxAd / 89 * 100, 'um')

def featureCalculateFd(path):
    # 默认灰度化读取
    image = cv.imread(path, 0)
    # 二值化
    ret, bn = cv.threshold(image, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)

    fd = fractal_dimension(bn)

    return fd

# ----------------------------------------------------------
#      分形维数计算
def fractal_dimension(Z, threshold=0.9):
    # Only for 2d image
    assert(len(Z.shape) == 2)

    # From https://github.com/rougier/numpy-100 (#87)
    def boxcount(Z, k):
        S = np.add.reduceat(
            np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0),
            np.arange(0, Z.shape[1], k), axis=1)

        # We count non-empty (0) and non-full boxes (k*k)
        return len(np.where((S > 0) & (S < k*k))[0])

    # Transform Z into a binary array
    Z = (Z < threshold)

    # Minimal dimension of image
    p = min(Z.shape)

    # Greatest power of 2 less than or equal to p
    n = 2**np.floor(np.log(p)/np.log(2))

    # Extract the exponent
    n = int(np.log(n)/np.log(2))

    # Build successive box sizes (from 2**n down to 2**1)
    sizes = 2**np.arange(n, 1, -1)

    # Actual box counting with decreasing size
    counts = []
    for size in sizes:
        counts.append(boxcount(Z, size))

    # Fit the successive log(sizes) with log (counts)
    coeffs = np.polyfit(np.log(sizes), np.log(counts), 1)
    return -coeffs[0]
# ----------------------------------------------------------